package com.xp.basic.heima.nio.netty.simpledemo.chat.client;

import com.xp.basic.heima.nio.netty.simpledemo.chat.message.ChatRequestMessage;
import com.xp.basic.heima.nio.netty.simpledemo.chat.message.LoginResponseMessage;
import com.xp.basic.heima.nio.netty.simpledemo.chat.message.LoginReuqestMessage;
import com.xp.basic.heima.nio.netty.simpledemo.chat.message.PingMessage;
import com.xp.basic.heima.nio.netty.simpledemo.chat.protocol.MessageCodec;
import com.xp.basic.heima.nio.netty.simpledemo.chat.protocol.ProcotolFrameDecoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

public class ChatClient {
    public static void main(String[] args) {
        NioEventLoopGroup loopGroup = new NioEventLoopGroup();
        MessageCodec MESSAGE_CODEC = new MessageCodec();
        LoggingHandler LOGGING_HANDLE = new LoggingHandler();
        // 倒计时锁，【主次线程之间 通信】
        CountDownLatch WAIT_FOR_LOGIN = new CountDownLatch(1); // 初始基数1，减为零才继续往下运行，否则等待
        // 登录状态 初始值 false 【主次线程之间 共享变量】
        final AtomicBoolean LOGIN = new AtomicBoolean(false);
        try{
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(loopGroup);
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {
                @Override
                protected void initChannel(NioSocketChannel ch) {

                    ch.pipeline().addLast(new ProcotolFrameDecoder());
                    ch.pipeline().addLast(LOGGING_HANDLE);
                    ch.pipeline().addLast(MESSAGE_CODEC);
                    ch.pipeline().addLast(new IdleStateHandler(0,5,0, TimeUnit.SECONDS));

                    ch.pipeline().addLast("12364",new ChannelInboundHandlerAdapter(){
                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) {
                            // 1. 处理登录 [登录成功 登录状态=true]
                            if ((msg instanceof LoginResponseMessage responseMessage)) {
                                if(responseMessage.isSuccess()) LOGIN.set(true);

                                WAIT_FOR_LOGIN.countDown(); // 减一 唤醒 线程：system in
                            }
                        }

                        /**
                         * 连接建立后触发一次
                         */
                        @Override
                        public void channelActive(ChannelHandlerContext ctx) {
                            // 另起线程(不然会被主线程阻塞) 接受用户输入消息 【登录】
                            new Thread(()->{

                                final Scanner scanner = new Scanner(System.in);
                                System.out.println("请输入用户名");
                                final String username = scanner.nextLine();
                                System.out.println("请输入密码");
                                final String password = scanner.nextLine();
                                // 构造消息对象
                                final LoginReuqestMessage message = new LoginReuqestMessage(username, password);
                                message.setVersion(1);
                                message.setSerializeType(0);
                                message.setMessageType(message.getMessageType());
                                message.setSquenceId(1);
                                message.setContent(message);
                                // 发送消息
                                ctx.writeAndFlush(message);

                               /* // ###################### [ 2 ] ######################
                                log.debug("等待后续操作......");
                                try {
                                    WAIT_FOR_LOGIN.await(); // 【 阻塞住，等 channelRead响应回来时 继续运行 】
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }

                                // ###################### [ 4 ] ######################
                                // 登录失败 停止运行
                                if (!LOGIN.get())
                                {
                                    ctx.channel().close(); // 触发 【channel.closeFuture().sync(); 向下运行】
                                    return;
                                }*/

                                // 打印菜单
                                while (true)
                                {
                                    System.out.println("============ 功能菜单 ============");
                                    System.out.println("send [username] [content]");
                                    System.out.println("gsend [group name] [content]");
                                    System.out.println("gcreate [group name] [m1,m2,m3...]");
                                    System.out.println("gmembers [group name]");
                                    System.out.println("gjoin [group name]");
                                    System.out.println("gquit [group name]");
                                    System.out.println("quit");
                                    System.out.println("==================================");

                                    String command = scanner.nextLine();
                                    final String[] s = command.split(" ");
                                    switch (s[0])
                                    {
                                        case "send": // 发送消息
                                            ctx.writeAndFlush(new ChatRequestMessage(username, s[1], s[2]));
                                            break;
                                        /*case "gsend": // 群里 发送消息
                                            ctx.writeAndFlush(new GroupChatRequestMessage(username, s[1], s[2]));
                                            break;
                                        case "gcreate": // 创建群
                                            final Set<String> set = new HashSet(Arrays.asList(s[2].split(",")));
                                            set.add(username);
                                            ctx.writeAndFlush(new GroupCreateRequestMessage(s[1], set));
                                            break;
                                        case "gmembers": // 查看群列表
                                            ctx.writeAndFlush(new GroupMembersRequestMessage(s[1]));
                                            break;
                                        case "gjoin":
                                            ctx.writeAndFlush(new GroupJoinRequestMessage(username, s[1]));
                                            break;
                                        case "gquit":
                                            ctx.writeAndFlush(new GroupQuitRequestMessage(username, s[1]));
                                            break;
                                        case "quit":
                                            ctx.channel().close(); // 触发 【channel.closeFuture().sync(); 向下运行】
                                            return;*/
                                    }
                                }



                            },"system in").start();


                        }

                        @Override
                        public void channelInactive(ChannelHandlerContext ctx) {
                            System.out.println("Client...主动-连接已经断开，按任意键退出..");
                        }


                        @Override
                        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {

                            IdleStateEvent  idleStateEvent = (IdleStateEvent) evt;
                            //客户端发送 写心跳包
                            if (idleStateEvent.state() == IdleState.WRITER_IDLE) {
                                ByteBuf buffer = ctx.alloc().buffer();
                                PingMessage pingMessage = new PingMessage();
                                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                                ObjectOutputStream ops = new ObjectOutputStream(bos);
                                ops.writeObject(pingMessage);
                                buffer.writeBytes(bos.toByteArray());
                                ctx.writeAndFlush(buffer);
                            }
                        }
                    });
                }
            });
            ChannelFuture channelFuture = bootstrap.connect(new InetSocketAddress(8080)).sync();
            channelFuture.addListener(_ ->{

            });
            channelFuture.channel().closeFuture().sync();
        }catch (Exception e ){
            System.out.println("发生了异常："+e.getMessage());
        }finally {
            loopGroup.shutdownGracefully();
        }
    }
}
